﻿#if __ANDROID__
#region File and License Information
/*
<File>
	<License>
		Copyright © 2009 - 2017, Daniel Vaughan. All rights reserved.
		This file is part of Calcium (http://calciumsdk.net), 
		which is released under the MIT License.
		See file /Documentation/License.txt for details.
	</License>
	<CreationDate>2013-01-01 11:32:08Z</CreationDate>
</File>
*/
#endregion

using Android.App;
using Android.Content;
using Android.Net;
using Android.Net.Wifi;

using System;
using System.Net;

using Outcoder.ComponentModel;
using Outcoder.Net;

namespace Outcoder.Services.Implementation
{
	public class NetworkMonitoringService : ObservableObject, INetworkMonitoringService
	{
		const int DefaultSampleRateMs = 1000;
		WifiReceiver wifiReceiver;
		int sampleRateMs;

		public int SampleRateMs
		{
			get
			{
				return sampleRateMs;
			}
		}

		bool approachingDataLimit;

		public bool ApproachingDataLimit
		{
			get
			{
				return approachingDataLimit;
			}
			private set
			{
				bool temp = LimitData;
				if (Assign(ref approachingDataLimit, value) == AssignmentResult.Success)
				{
					if (temp != LimitData)
					{
						OnPropertyChanged(nameof(LimitData));
					}
				}
			}
		}

		bool roaming;

		public bool Roaming
		{
			get
			{
				return roaming;
			}
			private set
			{
				bool temp = LimitData;
				if (Assign(ref roaming, value) == AssignmentResult.Success)
				{
					if (temp != LimitData)
					{
						OnPropertyChanged(nameof(LimitData));
					} 
				}
			}
		}

		public virtual bool LimitData
		{
			get
			{
				return Roaming || ApproachingDataLimit;
			}
		}

		public NetworkConnectionType NetworkConnectionType { get; private set; }
		public event EventHandler<EventArgs> NetworkConnectionChanged;

		bool connected;

		public bool Connected
		{
			get
			{
				return connected;
			}
			set
			{
				Assign(ref connected, value);
			}
		}

		bool IsConnected(ConnectivityManager connectivityManager)
		{
			NetworkInfo info = connectivityManager.ActiveNetworkInfo;
			return info != null && info.IsConnected;
		}

		public NetworkMonitoringService(int sampleRateMs = DefaultSampleRateMs)
		{
			this.sampleRateMs = sampleRateMs;

			Update();

			try
			{
				wifiReceiver = new WifiReceiver(this);
				var context = Application.Context;
				context.RegisterReceiver(wifiReceiver, new IntentFilter(WifiManager.NetworkStateChangedAction));
			}
			catch (Exception ex)
			{
				throw new Exception("Unable to start NetworkMonitoringService. " +
									"Please ensure that you have set the permission in your manifest. " +
									"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />", ex);
			}
		}

		internal void HandleNetworkStatusChanged(object sender)
		{
			Update();

			UISynchronizationContext.Instance.InvokeIfRequired(() =>
				{
					NetworkConnectionChanged?.Invoke(this, EventArgs.Empty);

					IMessenger messenger;
					if (Dependency.TryResolve<IMessenger>(out messenger))
					{
						messenger.Publish(new NetworkAvailabilityChangedMessage(
							new NetworkConnectionInfo(NetworkConnectionType, LimitData)));
					}
				});
		}

		string ssid;

		public string Ssid
		{
			get
			{
				return ssid;
			}
			set
			{
				Assign(ref ssid, value);
			}
		}

		string GetSsid(WifiManager wifiManager = null)
		{
			if (wifiManager == null)
			{
				var context = Application.Context;
				wifiManager = (WifiManager)context.GetSystemService(Context.WifiService);
			}

			WifiInfo wifiInfo = wifiManager.ConnectionInfo;
			var result = wifiInfo.ToString();

			return result;
		}

		public void Update()
		{
			var context = Application.Context;
			var wifi = (WifiManager)context.GetSystemService(Context.WifiService);
			ConnectivityManager cm = (ConnectivityManager)context.GetSystemService(Context.ConnectivityService);
			Connected = IsConnected(cm);
			NetworkInfo info = cm.ActiveNetworkInfo;
			Roaming = info?.IsRoaming ?? false;
			Ssid = GetSsid(wifi);
			IPAddress = GetIPAddress();

			if (info != null && info.IsConnected)
			{
				if (info.Type == ConnectivityType.Wifi)
				{
					NetworkConnectionType = NetworkConnectionType.Lan;
				}
				else
				{
					NetworkConnectionType = NetworkConnectionType.MobileBroadband;
				}
			}
			else
			{
				NetworkConnectionType = NetworkConnectionType.None;
			}
		}

		string GetIPAddress()
		{
			IPAddress[] addresses = Dns.GetHostAddresses(Dns.GetHostName());
			string ipAddress = null;
			if (addresses != null && addresses[0] != null)
			{
				ipAddress = addresses[0].ToString();
			}

			return ipAddress;
		}

		string iPAddress;

		public string IPAddress
		{
			get
			{
				return iPAddress;
			}
			private set
			{
				Assign(ref iPAddress, value);
			}
		}
	}

	public class WifiReceiver : BroadcastReceiver
	{
		NetworkMonitoringService networkMonitoringService;

		public WifiReceiver(NetworkMonitoringService networkMonitoringService)
		{
			this.networkMonitoringService = ArgumentValidator.AssertNotNull(networkMonitoringService, "networkMonitoringService");
		}

		public override void OnReceive(Context context, Intent intent)
		{
			networkMonitoringService.HandleNetworkStatusChanged(this);

			//var wifi = (WifiManager)context.GetSystemService(Context.WifiService);
			//var state = wifi.WifiState;
			//			int wifiState = intent.GetIntExtra(WifiManager.ExtraWifiState, WifiState.Unknown);
			//		string wifiStateText = "No State";
			//
			//		switch (wifiState)
			//		{
			//			case WifiManager.WifiStateDisabling:
			//				wifiStateText = "WIFI_STATE_DISABLING";
			//				break;
			//			case WifiManager.WIFI_STATE_DISABLED:
			//				wifiStateText = "WIFI_STATE_DISABLED";
			//				break;
			//			case WifiManager.WIFI_STATE_ENABLING:
			//				wifiStateText = "WIFI_STATE_ENABLING";
			//				break;
			//			case WifiManager.WIFISTATEENABLED:
			//				wifiStateText = "WIFI_STATE_ENABLED";
			//				break;
			//			case WifiManager.WifiStateUnknown:
			//				wifiStateText = "WIFI_STATE_UNKNOWN";
			//				break;
			//			default:
			//				break;
		}
	}
}
#endif